﻿using System;
using System.Diagnostics;
using System.Net;
using System.ServiceModel.Description;
using System.Windows.Forms;
using System.Collections;
using System.Configuration;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;

using Microsoft.Xrm.Sdk.Query;
using System.Security;
using JulMar.Atapi;
using Microsoft.Xrm.Sdk.Messages;

using McTools.Xrm.Connection;


namespace TapiConnector
{
    public partial class MainForm : Form
    {
        enum ConnectionStatus { Connected, Pending, Failed };

        TapiManager tapiManager;
        ConnectionDetail cDetail;
        ConnectionManager cManager;
        IOrganizationService service;

        bool foundContact;
        DateTime startTime;
        DateTime endTime;
        Guid contactGuid;
        bool callProcessed;

        string baseURL;

        public MainForm()
        {
            InitializeComponent();

            // Setup the TAPI & CRM Connection Manager
            this.tapiManager = new TapiManager("TAPI Connector for Dynamics CRM 2011");
            this.cManager = new ConnectionManager();
            this.cManager.ConnectionSucceed += new ConnectionManager.ConnectionSucceedEventHandler(cManager_ConnectionSucceed);
            this.cManager.ConnectionFailed += new ConnectionManager.ConnectionFailedEventHandler(cManager_ConnectionFailed);

            // Load Connection Detail from Registry
            this.cDetail = LoadConnectionDetailFromRegistry();

            // Check if the service URL is set in the connection detail - if not, open the config
            if (cDetail.OrganizationServiceUrl == null) {
                menuProperties_Click(this, EventArgs.Empty);
            }
            
            SetStatusIcon(ConnectionStatus.Pending);
            this.cManager.ConnectToServer(cDetail);
        }

        private void SetStatusIcon(ConnectionStatus status)
        {
            if (status == ConnectionStatus.Connected)
            {
                notifyTrayForm.Text = "TAPI CRM Connector - Connected";
            } else if (status == ConnectionStatus.Pending)
            {
                notifyTrayForm.Text = "TAPI CRM Connector - Connecting...";
            }
            else if (status == ConnectionStatus.Failed)
            {
                notifyTrayForm.Text = "TAPI CRM Connector - Can't connect to server";
            }
        }

        public ConnectionDetail LoadConnectionDetailFromRegistry()
        {
            ConnectionDetail detail = new ConnectionDetail();
            try
            {
                // Get the connection string from the registry.
                if (Application.UserAppDataRegistry.GetValue("AuthType") != null)
                {
                    String authType = Application.UserAppDataRegistry.GetValue("AuthType").ToString();
                    detail.AuthType = AuthenticationProviderType.ActiveDirectory; // Default to AD

                    if (Enum.IsDefined(typeof(AuthenticationProviderType), authType))
                    {
                        detail.AuthType = (AuthenticationProviderType)Enum.Parse(typeof(AuthenticationProviderType), authType);
                    }
                }

                if (Application.UserAppDataRegistry.GetValue("ConnectionId") != null)
                {
                    detail.ConnectionId = new Guid(Application.UserAppDataRegistry.GetValue("ConnectionId").ToString());
                }

                if (Application.UserAppDataRegistry.GetValue("ConnectionName") != null)
                {
                    detail.ConnectionName = Application.UserAppDataRegistry.GetValue("ConnectionName").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("IsCustomAuth") != null)
                {
                    detail.IsCustomAuth = bool.Parse(Application.UserAppDataRegistry.GetValue("IsCustomAuth").ToString());
                }

                if (Application.UserAppDataRegistry.GetValue("UseSsl") != null)
                {
                    detail.UseSsl = bool.Parse(Application.UserAppDataRegistry.GetValue("UseSsl").ToString());
                }

                if (Application.UserAppDataRegistry.GetValue("UseIfd") != null)
                {
                    detail.UseIfd = bool.Parse(Application.UserAppDataRegistry.GetValue("UseIfd").ToString());
                }

                if (Application.UserAppDataRegistry.GetValue("UseOnline") != null)
                {
                    detail.UseOnline = bool.Parse(Application.UserAppDataRegistry.GetValue("UseOnline").ToString());
                }

                if (Application.UserAppDataRegistry.GetValue("UseOsdp") != null)
                {
                    detail.UseOsdp = bool.Parse(Application.UserAppDataRegistry.GetValue("UseOsdp").ToString());
                }

                if (Application.UserAppDataRegistry.GetValue("ServerName") != null)
                {
                    detail.ServerName = Application.UserAppDataRegistry.GetValue("ServerName").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("ServerPort") != null)
                {
                    detail.ServerPort = Application.UserAppDataRegistry.GetValue("ServerPort").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("Organization") != null)
                {
                    detail.Organization = Application.UserAppDataRegistry.GetValue("Organization").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("OrganizationFriendlyName") != null)
                {
                    detail.OrganizationFriendlyName = Application.UserAppDataRegistry.GetValue("OrganizationFriendlyName").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("OrganizationServiceUrl") != null)
                {
                    detail.OrganizationServiceUrl = Application.UserAppDataRegistry.GetValue("OrganizationServiceUrl").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("HomeRealmUrl") != null)
                {
                    detail.HomeRealmUrl = Application.UserAppDataRegistry.GetValue("HomeRealmUrl").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("UserDomain") != null)
                {
                    detail.UserDomain = Application.UserAppDataRegistry.GetValue("UserDomain").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("UserName") != null)
                {
                    detail.UserName = Application.UserAppDataRegistry.GetValue("UserName").ToString();
                }

                if (Application.UserAppDataRegistry.GetValue("UserPassword") != null)
                {
                    SecureString password = EncryptionUtils.DecryptString(Application.UserAppDataRegistry.GetValue("UserPassword").ToString());
                    detail.UserPassword = EncryptionUtils.ToInsecureString(password);
                    detail.SavePassword = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return detail;

        }

        public void SaveConnectionDetailToRegistry(ConnectionDetail detail)
        {
            try
            {
                if (detail == null)
                {
                    throw new NullReferenceException("No ConnectionDetail object exists to save to registry");
                }
                if (detail.AuthType != null)
                {
                    Application.UserAppDataRegistry.SetValue("AuthType", detail.AuthType);
                }
                if (detail.ConnectionId != null)
                {
                    Application.UserAppDataRegistry.SetValue("ConnectionId", detail.ConnectionId);
                }
                if (detail.ConnectionName != null)
                {
                    Application.UserAppDataRegistry.SetValue("ConnectionName", detail.ConnectionName);
                }

                Application.UserAppDataRegistry.SetValue("IsCustomAuth", detail.IsCustomAuth);
                Application.UserAppDataRegistry.SetValue("UseIfd", detail.UseIfd);
                Application.UserAppDataRegistry.SetValue("UseOnline", detail.UseOnline);
                Application.UserAppDataRegistry.SetValue("UseOsdp", detail.UseOsdp);
                Application.UserAppDataRegistry.SetValue("UseSsl", detail.UseSsl);
                Application.UserAppDataRegistry.SetValue("ServerName", detail.ServerName);
                Application.UserAppDataRegistry.SetValue("ServerPort", detail.ServerPort);
                Application.UserAppDataRegistry.SetValue("Organization", detail.Organization);
                Application.UserAppDataRegistry.SetValue("OrganizationFriendlyName", detail.OrganizationFriendlyName);
                Application.UserAppDataRegistry.SetValue("OrganizationServiceUrl", detail.OrganizationServiceUrl);

                if (detail.HomeRealmUrl != null)
                {
                    Application.UserAppDataRegistry.SetValue("HomeRealmUrl", detail.HomeRealmUrl);
                }
                else
                {
                    Application.UserAppDataRegistry.SetValue("HomeRealmUrl", "");
                }
                Application.UserAppDataRegistry.SetValue("UserDomain", detail.UserDomain);
                Application.UserAppDataRegistry.SetValue("UserName", detail.UserName);
                if (detail.SavePassword)
                {
                    SecureString password = EncryptionUtils.ToSecureString(detail.UserPassword);
                    Application.UserAppDataRegistry.SetValue("UserPassword", EncryptionUtils.EncryptString(password));
                }
                else
                {
                    // Delete password from registry if save password isn't ticked
                    if (Application.UserAppDataRegistry.GetValue("UserPassword") != null)
                    {
                        Application.UserAppDataRegistry.DeleteValue("UserPassword");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        // Occurs when the connection to a server failed
        void cManager_ConnectionFailed(object sender, ConnectionFailedEventArgs e)
        {
            // Clear the current organization service
            this.service = null;
            MessageBox.Show("Connection failed: " + e.FailureReason);
            SetStatusIcon(ConnectionStatus.Failed);
        }

        void cManager_ConnectionSucceed(object sender, ConnectionSucceedEventArgs e)
        {
            // Store connection Organization Service
            this.service = e.OrganizationService;
            SetStatusIcon(ConnectionStatus.Connected);
        }

        public string BaseURL
        {
            get
            {
                if (baseURL == null)
                {
                    if (cDetail.UseSsl && cDetail.ServerPort.Equals("443")) {
                        baseURL = "https://" + cDetail.ServerName + "/" + cDetail.Organization + "/";
                    }
                    else if (cDetail.UseSsl)
                    {
                        baseURL = "https://" + cDetail.ServerName + ":" + cDetail.ServerPort + "/" + cDetail.Organization + "/";
                    }
                    else if (!cDetail.UseSsl && cDetail.ServerPort.Equals("80"))
                    {
                        baseURL = "http://" + cDetail.ServerName + "/" + cDetail.Organization + "/";
                    }
                    else // Using HTTP and a nonstandard port
                    {
                        baseURL = "http://" + cDetail.ServerName + ":" + cDetail.ServerPort + cDetail.Organization + "/";
                    }
                }
                return baseURL;
            }
        }

        private void trayForm_Load(object sender, EventArgs e)
        {
            if (!this.tapiManager.Initialize())
            {
                MessageBox.Show("No Tapi devices found.");
                base.Close();
            }
            else
            {
                foreach (TapiLine line in this.tapiManager.Lines)
                {
                    try
                    {
                        line.NewCall += new EventHandler<NewCallEventArgs>(this.OnNewCall);
                        line.CallStateChanged += new EventHandler<CallStateEventArgs>(this.OnCallStateChanged);
                        //line.CallInfoChanged += new EventHandler<CallInfoChangeEventArgs>(this.OnCallInfoChanged);
                        line.Monitor();
                    }
                    catch (TapiException exception)
                    {
                        Console.WriteLine(exception.Message);
                    }
                }
            }

        }

        private void OnNewCall(object sender, NewCallEventArgs e)
        {
            TapiLine line = (TapiLine)sender;
            TapiCall call = e.Call;
            foundContact = false;

            if ((call.CallState == CallState.Offering) & (call.CallerId.Length > 2))
            {
                CallPopup(call.CallerId);
            }
            else if ((call.CallState == CallState.Connected) & (call.ConnectedId.Length > 2))
            {
                CallPopup(call.ConnectedId);
            }
        }

        private void OnCallStateChanged(object sender, CallStateEventArgs e)
        {
            TapiCall call = e.Call;
            if (foundContact && call.CallState == CallState.Connected)
            {
                startTime = DateTime.Now;
            }
            else if (foundContact && call.CallState == CallState.Disconnected)
            {
                endTime = DateTime.Now;
                if ((endTime - startTime).Seconds > 30)
                {
                    // Create call activity in CRM
                    Entity callActivity = new Entity("phonecall");
                    callActivity["subject"] = "Phone call";
                    callActivity["from"] = new EntityReference("contact", contactGuid);
                    callActivity["actualdurationminutes"] = (endTime - startTime).Minutes;
                    Guid _activityID = service.Create(callActivity);

                    // Create all skype messages and write them to server
                    //foreach (Entity skypeMessage in skypeMessages)
                    //{
                    //    skypeMessage["new_skypecallid"] = new EntityReference("new_skypecall", _skypeCallId);
                    //    _service.Create(skypeMessage);
                    //}

                    // Open up created Skype Call activity
                    Uri link = new Uri(BaseURL + "main.aspx?etn=phonecall&id=%7b" + _activityID.ToString() + "%7d&pagetype=entityrecord");
                    Process.Start(link.ToString());
                }
            }
        }

        private void CallPopup(String phoneNumber)
        {
            Guid contactGuidId;
            Guid accountID;
            string contactID;
            string firstName;
            string lastName;
            string email = string.Empty;
            string companyName;
            string jobTitle = string.Empty;

            // Search for the phone number
            EntityCollection returnCollection = SearchByPhoneNumber(phoneNumber);

            if (returnCollection != null || returnCollection.Entities.Count > 0)
            {
                contactID = returnCollection.Entities[0].Attributes["contactid"].ToString();
                contactGuidId = (Guid)returnCollection.Entities[0].Attributes["contactid"];
                firstName = returnCollection.Entities[0].Attributes["firstname"].ToString();
                lastName = returnCollection.Entities[0].Attributes["lastname"].ToString();
                companyName = "Hello world!";
                if (returnCollection.Entities[0].Attributes.Contains("emailaddress1"))
                {
                    email = returnCollection.Entities[0].Attributes["emailaddress1"].ToString();
                }
                if (returnCollection.Entities[0].Attributes.Contains("jobtitle"))
                {
                    jobTitle = returnCollection.Entities[0].Attributes["jobtitle"].ToString();
                }

                MessageForm form = MessageForm.getInstance();
                form.baseURL = BaseURL;
                form.fadeIn();
                form.FillData(firstName, lastName, email, companyName, jobTitle, contactGuidId, Guid.Empty);
                foundContact = true;
                contactGuid = contactGuidId;
            }

            callProcessed = true;
        }


        //public void OurCallStatus(Call call, TCallStatus status)
        //{
        //    // Always use try/catch with ANY Skype calls.
        //    try
        //    {
        //        // If Skype is ringing
        //        if (call.Status == TCallStatus.clsRinging)
        //        {
        //            if (callProcessed == false)
        //            {
        //                callProcessed = true;
        //                startTime = DateTime.Now;
        //            }
        //        }
        //        else
        //        if (call.Status == TCallStatus.clsInProgress)
        //        {
        //            startTime = DateTime.Now;
        //        }
        //        else
        //        if (call.Status == TCallStatus.clsCancelled || call.Status == TCallStatus.clsMissed)
        //        {
        //            callProcessed = false;
        //        }
        //        else
        //        // If call is finished create a Skype Call activity
        //        if (call.Status == TCallStatus.clsFinished && callProcessed)
        //        {
        //            callProcessed = false;
        //            MessageForm form = MessageForm.getInstance();
        //            form.fadeOut();
                    
        //            endTime = DateTime.Now;

        //            // Create Skype activity in CRM
        //            Entity skypeCall = new Entity("new_skypecall");
        //            skypeCall["subject"] = "Skype call";
        //            skypeCall["regardingobjectid"] = new EntityReference("account", accountID) ;
        //            skypeCall["new_contact"] = new EntityReference("contact", contactGuidId);
        //            skypeCall["actualdurationminutes"] = (endTime - startTime).Minutes;
        //            Guid _skypeCallId = _service.Create(skypeCall);

        //            // Create all skype messages and write them to server
        //            foreach (Entity skypeMessage in skypeMessages)
        //            {
        //                skypeMessage["new_skypecallid"] = new EntityReference("new_skypecall", _skypeCallId);
        //                _service.Create(skypeMessage);
        //            }

        //            // Open up created Skype Call activity
        //            Uri link = new Uri("http://" + crmServer + ":" + crmServerPort + "/" + crmOrgName + "/main.aspx?etn=new_skypecall&id=%7b" + _skypeCallId.ToString() + "%7d&pagetype=entityrecord");                                                  
        //            Process.Start(link.ToString());
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        MessageBox.Show(e.ToString());
        //    }
        //}


        public EntityCollection SearchByPhoneNumber(string phoneNumber)
        {
            EntityCollection result = null;
            try
            {
                if (service == null)
                {
                    cManager.ConnectToServer(cDetail);
                }
                if (service != null)
                {
                    ConditionExpression condition_mobilephone = new ConditionExpression("mobilephone", ConditionOperator.Equal, phoneNumber);
                    ConditionExpression condition_telephone1 = new ConditionExpression("telephone1", ConditionOperator.Equal, phoneNumber);
                    ConditionExpression condition_telephone2 = new ConditionExpression("telephone2", ConditionOperator.Equal, phoneNumber);
                    ConditionExpression condition_telephone3 = new ConditionExpression("telephone3", ConditionOperator.Equal, phoneNumber);

                    FilterExpression filter1 = new FilterExpression(LogicalOperator.Or);
                    filter1.Conditions.AddRange(condition_mobilephone, condition_telephone1, condition_telephone2, condition_telephone3);

                    QueryExpression phoneQuery = new QueryExpression("contact");
                    phoneQuery.ColumnSet.AddColumns("contactid", "firstname", "lastname", "emailaddress1", "jobtitle", "parentcustomerid");
                    phoneQuery.Criteria.AddFilter(filter1);

                    result = service.RetrieveMultiple(phoneQuery);
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine("Error when trying to look up phone number: " + e.Message );
            }

            return result;
        }


        private void notifyTrayForm_DoubleClick(object sender, EventArgs e)
        {
            MessageForm m = MessageForm.getInstance();
            m.fadeIn();
        }

        private void menuProperties_Click(object sender, EventArgs e)
        {
            ConnectionForm cForm = new ConnectionForm(cDetail);
            cForm.StartPosition = FormStartPosition.CenterScreen;

            if (cForm.ShowDialog(this) == DialogResult.OK)
            {
                this.cDetail = cForm.CrmConnectionDetail;
                SaveConnectionDetailToRegistry(cDetail);
                //this.bValidate_Click(sender, e);
            }
            else
            {
                //this.bCancel_Click(sender, e);
                //return;
            }
        }

        private void menuExit_Click(object sender, EventArgs e)
        {
            this.Close();
            System.Windows.Forms.Application.Exit();
        }

        private void debugPhoneNumber_DoubleClick(object sender, EventArgs e)
        {
            CallPopup(debugPhoneNumber.Text);
        }

        private void debugPhoneNumber_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Enter)
            {
                CallPopup(debugPhoneNumber.Text);
            }
        }
    }
}
